package main

import (
	"errors"
	"net"
	"syscall"
)

const (
	HandleTypeTCP = 1

	HandleStatusClosing       = 0x00000001
	HandleStatusClosed        = 0x00000002
	HandleStatusActive        = 0x00000004
	HandleStatusRef           = 0x00000008
	HandleStatusInternal      = 0x00000010
	HandleStatusEndgameQueued = 0x00000020

	HandleStatusListening   = 0x00000040
	HandleStatusConnection  = 0x00000080
	HandleStatusShutting    = 0x00000100
	HandleStatusShut        = 0x00000200
	HandleStatusReadPartial = 0x00000400
	HandleStatusReadEof     = 0x00000800

	HandleStatusReading             = 0x00001000
	HandleStatusBound               = 0x00002000
	HandleStatusReadable            = 0x00004000
	HandleStatusWritable            = 0x00008000
	HandleStatusReadPending         = 0x00010000
	HandleStatusZeroRead            = 0x00040000
	HandleStatusBlockingWrites      = 0x00100000
	HandleStatusCancellationPending = 0x00200000

	HandleStatusIPV6 = 0x00400000

	HandleStatusTCPNodelay             = 0x01000000
	HandleStatusTCPKeepalive           = 0x02000000
	HandleStatusTCPSingleAccept        = 0x04000000
	HandleStatusTCPAcceptStateChanging = 0x08000000
	HandleStatusTCPSocketClosed        = 0x10000000
	HandleStatusTCPSharedSocket        = 0x20000000
)

func ISet(u uint32, f uint32) bool {
	return ((u & f) != 0)
}

// Bigger than we need, not too big to worry about overflow
const big = 0xFFFFFF

// Decimal to integer.
// Returns number, characters consumed, success.
func dtoi(s string) int {
	n := 0
	i := 0
	for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
		n = n*10 + int(s[i]-'0')
		if n >= big {
			return big
		}
	}
	return n
}

func ipToSockaddr(family int, ip net.IP, port int, zone string) (syscall.Sockaddr, error) {
	switch family {
	case syscall.AF_INET:
		if len(ip) == 0 {
			ip = net.IPv4zero
		}
		ip4 := ip.To4()
		sa := &syscall.SockaddrInet4{Port: port}
		copy(sa.Addr[:], ip4)
		return sa, nil
	case syscall.AF_INET6:
		if len(ip) == 0 || ip.Equal(net.IPv4zero) {
			ip = net.IPv6zero
		}
		ip6 := ip.To16()
		sa := &syscall.SockaddrInet6{Port: port, ZoneId: uint32(dtoi(zone))}
		copy(sa.Addr[:], ip6)
		return sa, nil
	}
	return nil, errors.New("invalid address family")
}

func tcpNodelay(fd int, on int) error {
	return syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, on)
}

func tcpKeepalive(fd int, on int) error {
	return syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, on)
}
